package com.example.audio_test.utils

import android.media.AudioFormat
import android.media.AudioRecord
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.io.FileInputStream
import java.io.FileOutputStream
import java.lang.Exception

/**
 *将pcm文件转换为 wav文件
 * @author : Kun
 * @date : 2021/6/18
 * @time : 16:05
 */
class PcmToWavUtils(var sampleRate: Int, var channel: Int, var encoding: Int) {
    private var mBufferSize: Int = 0

    init {
        mBufferSize = AudioRecord.getMinBufferSize(sampleRate, channel, encoding)
    }


    /**
     * pcm文件转wav文件
     */
    fun pcmToWav(inFileName: String, outFileName: String) {
        GlobalScope.launch {
            var fis: FileInputStream
            var fos: FileOutputStream

            var totalAudioLen: Long
            var totalDataLen: Long
            var longSampleRate = sampleRate
            //声道数量
            var channels = if (channel == AudioFormat.CHANNEL_IN_MONO) 1 else 2
            //数据传输速率,	该数值为:声道数×采样频率×每样本的数据位数/8。播放软件利用此值可以估计缓冲区的大小。
            //采样位数	存储每个采样值所用的二进制数位数。常见的位数有 4、8、12、16、24、32
            var byteRate = channels * sampleRate * 16 / 8

            var data = ByteArray(mBufferSize)

            try {
                fis = FileInputStream(inFileName)
                fos = FileOutputStream(outFileName)
                totalAudioLen = fis.channel.size()
                totalDataLen = totalAudioLen + 36

                writeWaveFileHeader(
                    fos,
                    totalAudioLen,
                    totalDataLen,
                    longSampleRate,
                    channels,
                    byteRate
                )

                while (fis.read(data) != -1) {
                    fos.write(data)
                }

                fis.close()
                fos.close()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    /**
     * 写入文件头
     */
    private fun writeWaveFileHeader(
        outputStream: FileOutputStream,
        totalAudioLen: Long,
        totalDataLen: Long,
        longSampleRate: Int,
        channels: Int,
        byteRate: Int
    ) {
        var header = ByteArray(44)
        //文档标识 4字节  大写字符串"RIFF",标明该文件为有效的 RIFF 格式文档。
        header[0] = 'R'.toByte()
        header[1] = 'I'.toByte()
        header[2] = 'F'.toByte()
        header[3] = 'F'.toByte()
        //文件数据长度 4字节 从下一个字段首地址开始到文件末尾的总字节数。该字段的数值加 8 为当前文件的实际长度。
        //末位先放
        header[4] = totalDataLen.and(0xff.toLong()).toByte()
        header[5] = (totalDataLen.shr(8)).and(0xff.toLong()).toByte()
        header[6] = (totalDataLen.shr(16)).and(0xff.toLong()).toByte()
        header[7] = (totalDataLen.shr(24)).and(0xff.toLong()).toByte()
        //文件格式类型  4字节  所有 WAV 格式的文件此处为字符串"WAVE",标明该文件是 WAV 格式文件。
        header[8] = 'W'.toByte()
        header[9] = 'A'.toByte()
        header[10] = 'V'.toByte()
        header[11] = 'E'.toByte()
        //格式块标识  4字节  小写字符串,"fmt "。
        header[12] = 'f'.toByte()
        header[13] = 'm'.toByte()
        header[14] = 't'.toByte()
        header[15] = ' '.toByte()
        //格式块长度  4字节  其数值不确定,取决于编码格式。可以是 16、 18 、20、40 等。
        header[16] = 16
        header[17] = 0
        header[18] = 0
        header[19] = 0
        //编码格式代码  2字节 常见的 WAV 文件使用 PCM 脉冲编码调制格式,该数值通常为 1
        header[20] = 1
        header[21] = 0
        //声道个数  2字节  单声道为 1,立体声或双声道为 2
        header[22] = channels.toByte()
        header[23] = 0
        //采样频率 4字节	每个声道单位时间采样次数。常用的采样频率有 11025, 22050 和 44100 kHz。
        //末位先放
        header[24] = longSampleRate.and(0xff).toByte()
        header[25] = (longSampleRate.shr(8)).and(0xff).toByte()
        header[26] = (longSampleRate.shr(16)).and(0xff).toByte()
        header[27] = (longSampleRate.shr(24)).and(0xff).toByte()
        //数据传输速率  4字节  该数值为:声道数×采样频率×每样本的数据位数/8。播放软件利用此值可以估计缓冲区的大小。
        header[28] = byteRate.and(0xff).toByte()
        header[29] = (byteRate.shr(8)).and(0xff).toByte()
        header[30] = (byteRate.shr(16)).and(0xff).toByte()
        header[31] = (byteRate.shr(24)).and(0xff).toByte()
        //数据块对齐单位  2字节  采样帧大小。该数值为:声道数×位数/8。播放软件需要一次处理多个该值大小的字节数据,用该数值调整缓冲区。
        header[32] = (channels * 16 / 2).toByte()
        header[33] = 0
        //采样位数  2字节  存储每个采样值所用的二进制数位数。常见的位数有 4、8、12、16、24、32
        header[34] = 16
        header[35] = 0
        //格式块标识  4字节  小写字符串,"data"。
        header[36] = 'd'.toByte()
        header[37] = 'a'.toByte()
        header[38] = 't'.toByte()
        header[39] = 'a'.toByte()
        //数据长度  4字节  音频文件长度 不包括头文件的长度
        //末位先放
        header[40] = totalAudioLen.and(0xff.toLong()).toByte()
        header[41] = (totalAudioLen.shr(8)).and(0xff.toLong()).toByte()
        header[42] = (totalAudioLen.shr(16)).and(0xff.toLong()).toByte()
        header[43] = (totalAudioLen.shr(24)).and(0xff.toLong()).toByte()

        outputStream.write(header, 0, 44)
    }
}